package com.gwl.concurrent.notify;

import static java.lang.System.out; 

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

class Car { 
	private volatile boolean waxOn = false; 
	public synchronized void waxed() { 
		waxOn = true; 
		notifyAll(); 
	} 
	public synchronized void buffed() { 
		waxOn = false; 
		notifyAll(); 
	} 
	public synchronized void waitForWaxing() throws InterruptedException { 
		while(waxOn == false) 
			wait(); 
	} 
	public synchronized void waitForBuffing() throws InterruptedException { 
		while(waxOn == true) 
			wait(); 
	}
	
} 
class WaxOn implements Runnable {
	private Car car; 
	public WaxOn(Car c) { 
		car = c; 
	} 
	@Override
	public void run() {
		try{ 
			while(!Thread.interrupted()) { 
				out.println("Wax On! "); 
				TimeUnit.MILLISECONDS.sleep(200); 
				car.waxed(); 
				car.waitForBuffing(); 
			}
		} catch(InterruptedException e) { 
			out.println("Wax On InterruptedException! "); 
		}
		out.println("Wax On Exit! "); 
	}
	
} 
class WaxOff implements Runnable {
	private Car car; 
	public WaxOff(Car c) { 
		car = c; 
	}
	@Override
	public void run() {
		try{ 
			while(!Thread.interrupted()) { 
				car.waitForWaxing(); 
				TimeUnit.MILLISECONDS.sleep(600); 
				out.println("Wax Off! "); 
				car.buffed(); 
			}
		} catch(InterruptedException e) { 
			out.println("Wax Off InterruptedException! "); 
		}
		out.println("Wax Off Exit! "); 
	} 
	
}

public class WaxOMatic {
	/**
	 * @param args
	 * @throws InterruptedException 
	 */
	public static void main(String[] args) throws InterruptedException { 
		Car car = new Car(); 
		ExecutorService exec = Executors.newCachedThreadPool(); 
		exec.execute(new WaxOn(car)); 
		exec.execute(new WaxOff(car)); 
		TimeUnit.SECONDS.sleep(2); 
		exec.shutdownNow(); 
	} 

}
